import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as dat from "lil-gui";
import CANNON from "cannon";
import { CannonDebugRenderer } from "./debug"
import { getRandomInt, sleep } from "@/core/tooler";

//晃动竹筒

export function start() {
    THREE.ColorManagement.enabled = false;

    /**
     * Debug
     */
    const gui = new dat.GUI();
    const debugObject: any = {};

    debugObject.createSphere = () => {
        createSphere(Math.random() * 0.5, {
            x: (Math.random() - 0.5) * 3,
            y: 3,
            z: (Math.random() - 0.5) * 3,
        });
    };

    debugObject.createBox = () => {
        createBox(0.12, 3, 0.02, {
            x: (Math.random() - 0.5) * 1.2,
            y: 4 + Math.random(),
            z: (Math.random() - 0.5) * 1.2,
        }, 0.1);
    };

    debugObject.reset = () => {
        for (const object of objectsToUpdate) {
            //Remove body
            object.body.removeEventListener("collide", playHitSound);
            world.removeBody(object.body);

            //Remove Mesh
            scene.remove(object.mesh);
        }
    };

    gui.add(debugObject, "createSphere");
    gui.add(debugObject, "createBox");
    gui.add(debugObject, "reset");

    /**
     * Base
     */
    // Canvas
    const canvas: any = document.getElementById("canvas");

    // Scene
    const scene = new THREE.Scene();

    //Fog
    const fog = new THREE.Fog("#ffffff", 1, 15);
    scene.fog = fog;

    // const hitSound = new Audio("/sounds/hit.mp3");

    const playHitSound = (collision: any) => {
        const impactStrength = collision.contact.getImpactVelocityAlongNormal();
        // console.log("碰撞", collision);
        if (impactStrength > 1.5) {
            // hitSound.volume = Math.random();
            // hitSound.currentTime = 0;
            // hitSound.play();
        }
    };

    /**
     * Textures
     */
    const textureLoader = new THREE.TextureLoader();
    const cubeTextureLoader = new THREE.CubeTextureLoader();

    const environmentMapTexture = cubeTextureLoader.load([
        "/asset/img/px.png",
        "/asset/img/nx.png",
        "/asset/img/py.png",
        "/asset/img/ny.png",
        "/asset/img/pz.png",
        "/asset/img/nz.png",
    ]);

    /**
     * Physics
     */
    const world = new CANNON.World();
    world.broadphase = new CANNON.SAPBroadphase(world);
    world.allowSleep = true;
    world.gravity.set(0, -9.92, 0);

    //Materials
    const defaultMaterial = new CANNON.Material("default");

    const defaultContactMaterial = new CANNON.ContactMaterial(
        defaultMaterial,
        defaultMaterial,
        {
            friction: 0.1,
            restitution: 0.7,
        }
    );

    world.addContactMaterial(defaultContactMaterial);
    world.defaultContactMaterial = defaultContactMaterial;

    world.solver.iterations = 30;
    console.log("world", world)


    //Floor
    const floorShape = new CANNON.Plane();
    const floorBody = new CANNON.Body();
    floorBody.mass = 0;
    floorBody.addShape(floorShape);
    floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(-1, 0, 0), Math.PI * 0.5);
    world.addBody(floorBody);

    /**
     * Floor
     */
    const floor = new THREE.Mesh(
        new THREE.PlaneGeometry(30, 30),
        new THREE.MeshStandardMaterial({
            color: "#fefefe",
            // side: THREE.DoubleSide,
            metalness: 0.3,
            roughness: 0.4,
            envMap: environmentMapTexture,
            envMapIntensity: 0.5,
        })
    );
    floor.receiveShadow = true;
    floor.rotation.x = -Math.PI * 0.5;
    scene.add(floor);

    /**
     * Lights
     */
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.1);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.set(1024, 1024);
    directionalLight.shadow.camera.far = 15;
    directionalLight.shadow.camera.left = -7;
    directionalLight.shadow.camera.top = 7;
    directionalLight.shadow.camera.right = 7;
    directionalLight.shadow.camera.bottom = -7;
    directionalLight.position.set(5, 10, 5);
    scene.add(directionalLight);

    /**
     * Sizes
     */
    const sizes = {
        width: window.innerWidth,
        height: window.innerHeight,
    };

    window.addEventListener("resize", () => {
        // Update sizes
        sizes.width = window.innerWidth;
        sizes.height = window.innerHeight;

        // Update camera
        camera.aspect = sizes.width / sizes.height;
        camera.updateProjectionMatrix();

        // Update renderer
        renderer.setSize(sizes.width, sizes.height);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    });

    /**
     * Camera
     */
    // Base camera
    const camera = new THREE.PerspectiveCamera(
        75,
        sizes.width / sizes.height,
        0.1,
        100
    );
    camera.position.set(-1.65, 4.593, 8.069);
    scene.add(camera);

    console.log("camera", camera)

    var cannonDebugRenderer = new CannonDebugRenderer(scene, world, {});

    // Controls
    const controls = new OrbitControls(camera, canvas);
    // controls.enableZoom = false;
    controls.enableDamping = true;

    /**
     * Renderer
     */
    const renderer = new THREE.WebGLRenderer({
        canvas: canvas,
    });
    renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.setSize(sizes.width, sizes.height);
    renderer.setClearColor(0xffffff);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

    /**
     * Utils
     */
    const objectsToUpdate: any[] = [];

    //Sphere
    const sphereGeometry = new THREE.SphereGeometry(1, 20, 20);
    const sphereMaterial = new THREE.MeshStandardMaterial({
        metalness: 0.3,
        roughness: 0.4,
        envMap: environmentMapTexture,
    });
    const createSphere = (radius: number, position: any) => {
        const mesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
        mesh.scale.set(radius, radius, radius);
        mesh.castShadow = true;
        mesh.position.copy(position);
        scene.add(mesh);

        //Cannon
        const shape = new CANNON.Sphere(radius);
        const body = new CANNON.Body({
            mass: 1,
            position: new CANNON.Vec3(0, 4, 0),
            shape: shape,
            material: defaultMaterial,
        });
        body.position.copy(position);
        body.addEventListener("collide", playHitSound);
        world.addBody(body);

        body.allowSleep = false

        mesh.userData.body = body;

        objectsToUpdate.push({
            mesh,
            body,
        });
    };

    // createSphere(0.5, { x: 0, y: 3, z: 0 });

    //Box
    const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
    const boxMaterial = new THREE.MeshStandardMaterial({
        metalness: 0.3,
        roughness: 0.4,
        envMap: environmentMapTexture,
    });
    const createBox = (width: number, height: number, depth: number, position: any, mass = 1) => {
        const mesh = new THREE.Mesh(boxGeometry, boxMaterial);
        mesh.scale.set(width, height, depth);
        mesh.castShadow = true;
        mesh.position.copy(position);
        scene.add(mesh);

        //Cannon
        const shape = new CANNON.Box(
            new CANNON.Vec3(width * 0.5, height * 0.5, depth * 0.5)
        );
        const body = new CANNON.Body({
            mass,
            position: new CANNON.Vec3(0, 4, 0),
            shape: shape,
            material: defaultMaterial,
        });
        body.position.copy(position);
        body.addEventListener("collide", playHitSound);
        world.addBody(body);
        body.allowSleep = false

        mesh.userData.body = body;

        objectsToUpdate.push({
            mesh,
            body,
        });

        return { body, mesh };
    };

    let boxes = new THREE.Group();
    let body0: CANNON.Body;
    setView();
    function setView() {
        scene.add(boxes);
        scene.add(new THREE.AxesHelper(4))
        // createBox(1, 2, 0.2, { x: 0, y: 1, z: -2 }, 0);
        // createBox(1, 2, 0.2, { x: 0, y: 1, z: 2 }, 0);

        const quaternion = new CANNON.Quaternion();
        quaternion.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), Math.PI / 2); // 绕 y 轴旋转 90 度
        let r = 1;

        const Width = 1.8;
        const Height = 2;
        const Thickness = 0.2;

        let { body: body00, mesh: mesh0 } = createBox(Width, Thickness, Width, { x: 0, y: 2, z: 0 }, 0);//底

        body0 = body00;

        let { body: body1, mesh: mesh1 } = createBox(Thickness, Height, Width, { x: -r, y: 3, z: 0 }, 0);//左
        // body1.quaternion.copy(quaternion);

        let { body: body2, mesh: mesh2 } = createBox(Thickness, Height, Width, { x: r, y: 3, z: 0 }, 0);//右
        // body2.quaternion.copy(quaternion);

        let { body: body3, mesh: mesh3 } = createBox(Width, Height, Thickness, { x: 0, y: 3, z: -r }, 0);//后
        // const quaternion3 = new CANNON.Quaternion();
        // quaternion3.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), Math.PI / 5); // 绕 y 轴旋转 90 度
        // body3.quaternion.copy(quaternion3);

        let { body: body4, mesh: mesh4 } = createBox(Width, Height, Thickness, { x: 0, y: 3, z: r }, 0);//前
        // const quaternion4 = new CANNON.Quaternion();
        // quaternion4.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), -Math.PI / 5); // 绕 y 轴旋转 90 度
        // body4.quaternion.copy(quaternion4);

        boxes.add(mesh0)
        boxes.add(mesh1)
        boxes.add(mesh2)
        boxes.add(mesh3)
        boxes.add(mesh4)


        setTimeout(() => {
            let constraint0 = new CANNON.LockConstraint(body0, body1, {});
            world.addConstraint(constraint0)

            let constraint1 = new CANNON.LockConstraint(body1, body2, {});
            world.addConstraint(constraint1)
            let constraint2 = new CANNON.LockConstraint(body2, body3, {});
            world.addConstraint(constraint2)
            let constraint3 = new CANNON.LockConstraint(body3, body4, {});
            world.addConstraint(constraint3)
            addBars();
        }, 30);

    }

    async function addBars() {
        for (let i = 0; i < 30; i++) {
            await sleep(30);
            debugObject.createBox();
        }
    }

    window.addEventListener("click", handleClick)

    function handleClick(event: MouseEvent) {
        // 获取点击位置的屏幕坐标
        const mouse = new THREE.Vector2();
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        // 通过射线投射获取点击位置的物体
        const raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(boxes.children, true);

        if (intersects.length > 0) {
            const worldPosition = intersects[0].point;
            console.log("点击位置的世界坐标:", worldPosition);
            for (let i = 0; i < intersects.length; i++) {
                const obj = intersects[0].object;
                for (const object of objectsToUpdate) {
                    if (object.mesh == obj) {
                        object.mesh.userData.body.allowSleep = false;
                        // 给刚体施加沿 Y 轴方向的力
                        const force = new CANNON.Vec3(getRandomInt(-30, 30), getRandomInt(200, 800), getRandomInt(-30, 30));
                        const p = new CANNON.Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
                        console.log(p)
                        object.mesh.userData.body.applyForce(force, p);
                        console.log("点击", object.mesh)
                        return
                    }
                }
            }

        }

    }

    /**
     * Animate
     */
    const clock = new THREE.Clock();
    let oldElapsedTime = 0;

    // 定义摇晃力的参数
    const shakeForce = new CANNON.Vec3(0, 0, 1); // 在 Z 轴上施加摇晃力
    const shakeMagnitude = 10; // 摇晃力的大小
    let tid = 0;

    const tick = () => {
        const elapsedTime = clock.getElapsedTime();
        const deltaTime = elapsedTime - oldElapsedTime;
        oldElapsedTime = elapsedTime;

        if (++tid > 200) {
            tid = 0;
            const randomShake = new CANNON.Vec3(
                (Math.random() - 0.5) * 4,
                (Math.random() - 0.5) * 7,
                (Math.random() - 0.5) * 10
            )
            // 施加摇晃力到刚体
            // body0.applyForce(randomShake, body0.position);

            body0.velocity.copy(randomShake);
            console.log("roll")
        }



        //Update Physics World
        world.step(1 / 60, deltaTime, 3);

        for (const object of objectsToUpdate) {
            object.mesh.position.copy(object.mesh.userData.body.position);
            object.mesh.quaternion.copy(object.mesh.userData.body.quaternion);
        }

        cannonDebugRenderer.update();

        // Update controls
        // controls.update();

        // Render
        renderer.render(scene, camera);

        // Call tick again on the next frame
        window.requestAnimationFrame(tick);
    };

    tick();
}